# forward-compat boilerplate
from __future__ import absolute_import
from __future__ import with_statement
__metaclass__ = type

import sys
import logging


DEBUG0 = logging.DEBUG
DEBUG1 = DEBUG0+1
DEBUG2 = DEBUG0+2
DEBUG3 = DEBUG0+3

logging.addLevelName(DEBUG0, 'DEBUG0')
logging.addLevelName(DEBUG1, 'DEBUG1')
logging.addLevelName(DEBUG2, 'DEBUG2')
logging.addLevelName(DEBUG3, 'DEBUG3')

getLogger = logging.getLogger




def color_detect(*args, **kw):
    format = '%(asctime)s %(levelname)-5.5s [%(name)s] %(message)s'
    normal = logging.Formatter(format)
    pretty = PrettyThreadFormatter(*args, **kw)
    from fenton import console
    return console.colors.capable() and pretty or normal


def _calling_frame(offset=0):
    return sys._getframe(offset+3).f_globals.get('__name__', None)


def _getlogger(offset=0):
    return getLogger(_calling_frame(offset))


@apply
def debugcolor():
    d = [0]
    def f():
        d[0] = (d[0] + 1) % 4
        return d[0]
    return f


def log_exception(msg=None):
    E, e, tb = sys.exc_info()
    if getattr(e, '_logged', False):
        return
    log = _getlogger(1)
    prefix = '%s\n' % (msg or '')
    from fenton.util import color_tb
    trace = ''.join(color_tb(tb))
    if e is None:
        postfix = E
    else:
        postfix = '%s: %s' % (E.__name__, e)
    msg = '%s%s%s\n' % (prefix, trace, postfix)
    log.error(msg)


def log_stack(msg=None, limit=None):
    from fenton.util import color_stack
    log = _getlogger()
    prefix = '%s\n' % (msg or '')
    trace = ''.join(color_stack(f=sys._getframe(2), limit=limit))
    msg = '%s%s\n' % (prefix, trace)
    log.error(msg)




class PrettyFormatter(logging.Formatter):
    _format_prefix = None
    _colors = None
    def formatTime(self, rec):
        import time
        t = time.localtime(rec.created)
        return '%s.%03d' % (time.strftime('%H:%M:%S', t), rec.msecs)

    def format(self, rec):
        colorize = self.colors.get(rec.levelno)
        msg = '%s %s' % (colorize(rec.name), rec.getMessage())
        prefix = self._format_prefix and self._format_prefix(rec) or ''
        return prefix + msg

    @property
    def colors(self):
        if self._colors is None:
            from fenton import console
            self._colors =  {
                logging.CRITICAL:   console.colors.LightRed,
                logging.ERROR:      console.colors.Yellow,
                logging.WARNING:    console.colors.Brown,
                logging.INFO:       console.colors.LightGreen,
                logging.DEBUG:      console.colors.LightBlue,
                DEBUG1:             console.colors.LightPurple,
                DEBUG2:             console.colors.Purple,
                DEBUG3:             console.colors.Blue,
                logging.NOTSET:     console.colors.White
            }
        return self._colors



class PrettyThreadFormatter(PrettyFormatter):
    def _format_prefix(self, rec):
        import thread
        from fenton import console
        from fenton.util import byteswap, uint
        id = uint(thread.get_ident())
        return '%s ' % console.colors.random('%x'%id, byteswap(id))




class LazyLogger:

    def __getattr__(self, attr):
        return getattr(_getlogger(), attr)

    def exception(self, msg=None):
        log_exception(msg)

    def stack(self, msg=None, limit=None):
        log_stack(msg, limit)

    def debug(self, *args, **kw):
        _getlogger().log(DEBUG0 + debugcolor(), *args, **kw)

    def caller(self, msg, *args, **kw):
        from fenton.util import getcaller
        level = kw.pop('level', 1)
        scope = getcaller(level)
        msg = ('[%s:%s] ' % (scope['file'], scope['line'])) + msg
        _getlogger().log(DEBUG0, msg, *args, **kw)



log = LazyLogger()




